package org.chemodansama.fifteen;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;

import android.content.Context;

public class HallOfFame {
    
    public class Entry {
        private String mName;
        private int mResult;
        
        Entry(String name, int result) {
            mName = name;
            mResult = result;
        }
        
        public String getName() {
            return mName;
        }
        
        public int getResult() {
            return mResult;
        }
    }
    
    public static final String HALL3x3 = "3x3.dat";
    public static final String HALL4x4 = "4x4.dat";
    
    public static final int MAX_NAME_LENGTH = 16;
    public static final int RECORDS_LIMIT = 3; 
    
    private static final HashMap<String, HallOfFame> mInstances = 
        new HashMap<String, HallOfFame>();
    
    private static final String DEFAULT_NAME = "unknown";
    
    private static final int DEFAULT_RESULT = 999;
    
    synchronized public static HallOfFame getInstance(Context context, 
            String fileName) {
        
        HallOfFame hof = mInstances.get(fileName);
        
        if (hof == null) {
            hof = new HallOfFame(context, fileName);
            mInstances.put(fileName, hof);
        }
        
        return hof;
    }
    
    private final ArrayList<Entry> mEntries = new ArrayList<HallOfFame.Entry>();

    private final Context mContext;
    private final String mFileName;
    
    private HallOfFame(Context context, String fileName) {
        
        mContext = context;
        
        mFileName = fileName;
        
        if (!loadData(context, fileName)) {
            writeData(context);
        }
    }
    
    synchronized public Entry getEntry(int i) {
        if ((i >= 0) && (i < mEntries.size())) {
            return mEntries.get(i);
        } else {
            return new Entry(DEFAULT_NAME, DEFAULT_RESULT);
        }
    }
    
    private boolean loadData(Context context, String fileName) {

        mEntries.clear();
        
        try {
            FileInputStream in = context.openFileInput(fileName);
            
            InputStreamReader sr = new InputStreamReader(in);
            
            char[] inputBuffer = new char[255];
            
            sr.read(inputBuffer, 0, 255);
            
            String s = new String(inputBuffer);
            
            String[] sa = s.split(";");
            
            for (int i = 0; i < sa.length; i++) {
                String[] a = sa[i].split("=");
                
                if (a.length != 2) {
                    continue;
                }
                
                mEntries.add(new Entry(a[0], Integer.parseInt(a[1])));
            }
            
            for (int i = mEntries.size(); i < RECORDS_LIMIT; i++) {
                mEntries.add(new Entry(DEFAULT_NAME, DEFAULT_RESULT));
            }
            
            sr.close();
            
        } catch (IOException e) {
            
            mEntries.clear();
            
            for (int i = 0; i < RECORDS_LIMIT; i++) {
                mEntries.add(new Entry(DEFAULT_NAME, DEFAULT_RESULT));
            }
            
            return false;
        }
        
        return true;
    }
    
    synchronized public static String get15HallName(int puzzleSize) {
        if (puzzleSize == 3) {
            return HallOfFame.HALL3x3;
        } else {
            return HallOfFame.HALL4x4;
        }
    }
    
    synchronized public int getResultPos(int result) {
        
        for (int i = 0; i < RECORDS_LIMIT; i++) {
            Entry e = getEntry(i);

            if (e == null) {
                continue;
            }
            
            if (e.getResult() > result) {
                return i;
            }
        }
        
        return -1;
    }
    
    synchronized public void reset() {
        mEntries.clear();
        for (int i = 0; i < RECORDS_LIMIT; i++) {
            mEntries.add(new Entry(DEFAULT_NAME, DEFAULT_RESULT));
        }
        writeData(mContext);
    }
    
    synchronized public boolean putValue(String playerName, int result) {
        
        for (int i = 0; i < mEntries.size(); i++) {
            
            if (mEntries.get(i).getResult() > result) {
                
                mEntries.add(i, new Entry(playerName, result));
                
                while (mEntries.size() > RECORDS_LIMIT) {
                    mEntries.remove(mEntries.size() - 1);
                }
                
                writeData(mContext);
                
                return true;
            }
        }
        
        return false;
    }
    
    private void writeData(Context context) {
        try {
            FileOutputStream os = context.openFileOutput(mFileName, 
                                                         Context.MODE_PRIVATE);
            
            OutputStreamWriter sw = new OutputStreamWriter(os);
            
            String s = "";
            
            for (int i = 0; i < RECORDS_LIMIT; i++) {
                Entry e = getEntry(i);
               
                s += e.getName() + "=" + e.getResult() + ";";
            }
            
            sw.write(s);
            sw.flush();
            sw.close();
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
